home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume1 / cshar < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  23.3 KB

  1. From: decvax!wanginst!perlman
  2. Date: Sun, 2 Jun 85 16:35:35 edt
  3. Subject: improved version of shar (shell archiver)
  4.  
  5. Here is a new version of my C shar program.
  6. I have made some changes in how existing files are handled;
  7. now shar will not overwrite existing files.
  8. I have worked with lint and prof to improve the code,
  9. especially the speed.  You can try it out for yourself.
  10.  
  11. Gary Perlman  Wang Institute  Tyngsboro, MA 01879  (617) 649-9731
  12. UUCP: decvax!wanginst!perlman             CSNET: perlman@wanginst
  13.  
  14. #! /bin/sh
  15. # This is a shell archive, meaning:
  16. # 1. Remove everything above the #! /bin/sh line.
  17. # 2. Save the resulting text in a file.
  18. # 3. Execute the file with /bin/sh (not csh) to create the files:
  19. #    shar.1
  20. #    shar.c
  21. #    traverse.3
  22. #    traverse.c
  23. #    getopt.3
  24. #    getopt.c
  25. #    Makefile
  26. # This archive created: Tue Jun  4 01:07:18 1985
  27. # By:    Gary Perlman (Wang Institute, Tyngsboro, MA 01879 USA)
  28. export PATH; PATH=/bin:$PATH
  29. echo shar: extracting "'shar.1'" '(2691 characters)'
  30. if test -f 'shar.1'
  31. then
  32.     echo shar: will not over-write existing file "'shar.1'"
  33. else
  34. sed 's/^    X//' << \SHAR_EOF > 'shar.1'
  35.     X.TH SHAR 1net "June 3, 1985" "UNIX User's Manual" "Wang Institute"
  36.     X.SH NAME
  37.     Xshar \- create file storage archive for extraction by /bin/sh
  38.     X.SH SYNOPSIS
  39.     X.B shar
  40.     X[-abcsv] [-d delim] [-p prefix] files
  41.     X.SH DESCRIPTION
  42.     X.I shar
  43.     Xprints its input files with special command lines around them
  44.     Xto be used by the shell,
  45.     X.I /bin/sh ,
  46.     Xto extract them later.
  47.     XThe output can be filtered through the shell to
  48.     Xrecreate copies of the original files.
  49.     X.PP
  50.     X.I shar
  51.     Xallows directories to be named, and
  52.     X.I shar
  53.     Xprints the necessary commands
  54.     X.ul
  55.     X(mkdir & cd)
  56.     Xto create new directories and fill them.
  57.     X.I shar
  58.     Xwill emit commands to make executable plain files executable.
  59.     X.I shar will not allow existing files to be over-written;
  60.     Xsuch files must be removed by the file extractor.
  61.     X.SH OPTIONS
  62.     X.de OP
  63.     X.TP
  64.     X.B -\\$1
  65.     X..
  66.     X.OP a
  67.     XAll the options.
  68.     XThe options:
  69.     X.B "-v -c -b -p <tab>X"
  70.     Xare implied.
  71.     X.OP s
  72.     XSilent running.
  73.     XAll checking and extra output is inhibited.
  74.     X.OP v
  75.     XPrint verbose feedback messages about what
  76.     X.I shar
  77.     Xis doing to be printed during extraction.
  78.     XSizes of plain files are echoed to allow a simple validity check.
  79.     X.OP c
  80.     XCheck file size on extraction by counting characters.
  81.     XAn error message is reported to the person doing the
  82.     Xextraction if the sizes don't match.
  83.     XOne reason why the sizes may not match is that
  84.     X.I shar
  85.     Xwill append a newline to complete incomplete last lines;
  86.     X.I shar
  87.     Xprints a message that mentions added newlines.
  88.     XAnother reason why the sizes may not match is that some
  89.     Xnetwork mail programs remove non-whitespace control characters.
  90.     X.I shar
  91.     Xprints a message that mentions control characters to the extractor.
  92.     X.OP b
  93.     XExtract files into basenames so that files with absolute path names
  94.     Xare put into the current directory.
  95.     XThis option has strange effects when directories are archived.
  96.     X.OP d delim
  97.     XUse this as the ``end of file'' delimiter instead of the default.
  98.     XThe only reason to change it is if you suspect an file
  99.     Xcontains the default delimiter:
  100.     X.B SHAR_EOF.
  101.     X.OP p prefix
  102.     XUse this as the prefix to each line of the archived files.
  103.     XThis is to make sure that special characters at the start of lines are not
  104.     Xeaten up by programs like mailers.
  105.     XIf this option is used,
  106.     Xthe files will be extracted with the stream editor
  107.     X.B sed
  108.     Xrather than
  109.     X.B cat
  110.     Xso it is more efficient and portable to avoid setting the prefix,
  111.     Xthough perhaps less safe if you don't know what is in the files.
  112.     X.SH "SEE ALSO
  113.     Xtar(1), cpio(1), tp(1), sh(1)
  114.     X.SH AUTHOR
  115.     XGary Perlman
  116.     X(based on a shell version by James Gosling,
  117.     Xwith additions motivated by
  118.     XDerek Zahn,
  119.     XMichael Thompson,
  120.     XH. Morrow Long,
  121.     XFred Avolio,
  122.     XGran Uddeborg,
  123.     X&
  124.     XChuck Wegrzyn)
  125.     X.SH LIMITATIONS
  126.     X.I shar
  127.     Xdoes not know anything about
  128.     Xlinks between files
  129.     Xor binary files.
  130. SHAR_EOF
  131. if test 2691 -ne "`wc -c < 'shar.1'`"
  132. then
  133.     echo shar: error transmitting "'shar.1'" '(should have been 2691 characters)'
  134. fi
  135. fi # end of overwriting check
  136. echo shar: extracting "'shar.c'" '(8881 characters)'
  137. if test -f 'shar.c'
  138. then
  139.     echo shar: will not over-write existing file "'shar.c'"
  140. else
  141. sed 's/^    X//' << \SHAR_EOF > 'shar.c'
  142.     X#include <stdio.h>
  143.     X#include <sys/types.h>
  144.     X#include <sys/stat.h>
  145.     X#include <ctype.h>
  146.     X
  147.     X/*{
  148.     XShar puts readable text files together in a package
  149.     Xfrom which they are easy to extract.  The original version
  150.     Xwas a shell script posted to the net, shown below:
  151.     X    #Date: Mon Oct 18 11:08:34 1982
  152.     X    #From: decvax!microsof!uw-beave!jim (James Gosling at CMU)
  153.     X    AR=$1
  154.     X    shift
  155.     X    for i do
  156.     X        echo a - $i
  157.     X        echo "echo x - $i" >>$AR
  158.     X        echo "cat >$i <<'!Funky!Stuff!'" >>$AR
  159.     X        cat $i >>$AR
  160.     X        echo "!Funky!Stuff!" >>$AR
  161.     X    done
  162.     XI rewrote this version in C to provide better diagnostics
  163.     Xand to run faster.  The major difference is that my version
  164.     Xdoes not affect any files because it prints to the standard
  165.     Xoutput.  Mine also has several options.
  166.     X
  167.     XGary Perlman/Wang Institute/Tyngsboro, MA/01879/(617) 649-9731
  168.     X
  169.     XMany enhancements motivated by Michael Thompson.
  170.     X
  171.     XDirectory archiving motivated by Derek Zahn @ wisconsin
  172.     X    His version had some problems, so I wrote a general
  173.     X    routine for traversing a directory hierarchy.  It
  174.     X    allows marching through a directory on old and new
  175.     X    UNIX systems.
  176.     X}*/
  177.     X
  178.     X/* COMMANDS */
  179.     X#define    EXTRACT "#! /bin/sh"     /* magic exec string at shar file start */
  180.     X#define    PATH    "/bin:$PATH"     /* search path for programs */
  181.     X#define    CAT     "cat";           /* /bin/cat */
  182.     X#define    SED     "sed 's/^%s//'"  /* /bin/sed removes Prefix from lines */
  183.     X#define    MKDIR   "mkdir"          /* make a new dirctory */
  184.     X#define    CHMOD   "chmod +x"       /* change file protection (for executables) */
  185.     X#define    CHDIR   "cd"             /* change current directory */
  186.     X#define    TEST    "test"           /* /bin/test files */
  187.     X#define    WC_C    "wc -c <"        /* counts chars in file */
  188.     X#define    ECHO    "echo shar"      /* echo a message to extractor */
  189.     X
  190.     Xmain (argc, argv) char **argv;    
  191.     X    {
  192.     X    int     shar ();
  193.     X    int     optind;
  194.     X    if ((optind = initial (argc, argv)) < 0)
  195.     X        exit (1);
  196.     X    if (header (argc, argv, optind))
  197.     X        exit (2);
  198.     X    while (optind < argc)
  199.     X        traverse (argv[optind++], shar);
  200.     X    footer ();
  201.     X    exit (0);
  202.     X    }
  203.     X
  204.     X/*            OPTIONS            */
  205.     Xtypedef    int    lgl;
  206.     X#define    true    ((lgl) 1)
  207.     X#define    false    ((lgl) 0)
  208.     Xint     Lastchar;   /* the last character printed */
  209.     Xint     Ctrlcount;  /* how many bad control characters are in file */
  210.     X
  211.     X#define    USAGE "[-abcsv] [-p prefix] [-d delim] files > archive"
  212.     X#define    OPTSTRING "abcsvp:d:"
  213.     X
  214.     Xlgl     Verbose = false;       /* provide append/extract feedback */
  215.     Xlgl     Basename = false;      /* extract into basenames */
  216.     Xlgl     Count = false;         /* count characters to check transfer */
  217.     Xlgl     Silent = false;        /* turn off all verbosity */
  218.     Xchar    *Delim = "SHAR_EOF";   /* put after each file */
  219.     Xchar    Filter[100] = CAT;     /* used to extract archived files */
  220.     Xchar    *Prefix = NULL;        /* line prefix to avoid funny chars */
  221.     X
  222.     Xint /* returns the index of the first operand file */
  223.     Xinitial (argc, argv) char **argv;
  224.     X    {
  225.     X    int     errflg = 0;
  226.     X    extern    int     optind;
  227.     X    extern    char    *optarg;
  228.     X    int     C;
  229.     X    while ((C = getopt (argc, argv, OPTSTRING)) != EOF)
  230.     X        switch (C)
  231.     X            {
  232.     X            case 'v': Verbose = true; break;
  233.     X            case 'c': Count = true; break;
  234.     X            case 'b': Basename = true; break;
  235.     X            case 'd': Delim = optarg; break;
  236.     X            case 's': /* silent running */
  237.     X                Silent = true;
  238.     X                Verbose = false;
  239.     X                Count = false;
  240.     X                Prefix = NULL;
  241.     X                break;
  242.     X            case 'a': /* all the options */
  243.     X                Verbose = true;
  244.     X                Count = true;
  245.     X                Basename = true;
  246.     X                /* fall through to set prefix */
  247.     X                optarg = "    X";
  248.     X            case 'p': (void) sprintf (Filter, SED, Prefix = optarg); break;
  249.     X            default: errflg++;
  250.     X            }
  251.     X    if (errflg || optind == argc)
  252.     X        {
  253.     X        if (optind == argc)
  254.     X            fprintf (stderr, "shar: No input files\n");
  255.     X        fprintf (stderr, "USAGE: shar %s\n", USAGE);
  256.     X        return (-1);
  257.     X        }
  258.     X    return (optind);
  259.     X    }
  260.     X
  261.     Xheader (argc, argv, optind)
  262.     Xchar    **argv;
  263.     X    {
  264.     X    int     i;
  265.     X    lgl     problems = false;
  266.     X    long    clock;
  267.     X    char    *ctime ();
  268.     X    char    *getenv ();
  269.     X    char    *NAME = getenv ("NAME");
  270.     X    char    *ORG = getenv ("ORGANIZATION");
  271.     X    for (i = optind; i < argc; i++)
  272.     X        if (access (argv[i], 4)) /* check read permission */
  273.     X            {
  274.     X            fprintf (stderr, "shar: Can't read '%s'\n", argv[i]);
  275.     X            problems++;
  276.     X            }
  277.     X    if (problems) return (problems);
  278.     X    /*    I have given up on putting a cut line in the archive.
  279.     X        Too many people complained about having to remove it.
  280.     X        puts ("-----cut here-----cut here-----cut here-----cut here-----");
  281.     X    */
  282.     X    puts (EXTRACT);
  283.     X    puts ("# This is a shell archive, meaning:");
  284.     X    printf ("# 1. Remove everything above the %s line.\n", EXTRACT);
  285.     X    puts ("# 2. Save the resulting text in a file.");
  286.     X    puts ("# 3. Execute the file with /bin/sh (not csh) to create the files:");
  287.     X    for (i = optind; i < argc; i++)
  288.     X        printf ("#\t%s\n", argv[i]);
  289.     X    (void) time (&clock);
  290.     X    printf ("# This archive created: %s", ctime (&clock));
  291.     X    if (NAME)
  292.     X        printf ("# By:\t%s (%s)\n", NAME, ORG ? ORG : "");
  293.     X    printf ("export PATH; PATH=%s\n", PATH);
  294.     X    return (0);
  295.     X    }
  296.     X
  297.     Xfooter ()
  298.     X    {
  299.     X    puts ("#\tEnd of shell archive");
  300.     X    puts ("exit 0");
  301.     X    }
  302.     X
  303.     Xarchive (input, output)
  304.     Xchar    *input, *output;
  305.     X    {
  306.     X    char    buf[BUFSIZ];
  307.     X    FILE    *ioptr;
  308.     X    if (ioptr = fopen (input, "r"))
  309.     X        {
  310.     X        if (Count == true)
  311.     X            {
  312.     X            Ctrlcount = 0;    /* no bad control characters so far */
  313.     X            Lastchar = '\n';  /* simulate line start */
  314.     X            }
  315.     X        printf ("%s << \\%s > '%s'\n", Filter, Delim, output);
  316.     X        if (Prefix)
  317.     X            {
  318.     X            while (fgets (buf, BUFSIZ, ioptr))
  319.     X                {
  320.     X                if (Prefix) outline (Prefix);
  321.     X                outline (buf);
  322.     X                }
  323.     X            }
  324.     X        else copyout (ioptr);
  325.     X        /* thanks to H. Morrow Long (ittvax!long) for the next fix */
  326.     X        if (Lastchar != '\n') /* incomplete last line */
  327.     X            putchar ('\n');   /* Delim MUST begin new line! */
  328.     X        puts (Delim);
  329.     X        if (Count == true && Lastchar != '\n')
  330.     X            printf ("%s: a missing newline was added to \"'%s'\"\n", ECHO, input);
  331.     X        if (Count == true && Ctrlcount)
  332.     X            printf ("%s: %d control character%s may be missing from \"'%s'\"\n",
  333.     X                ECHO, Ctrlcount, Ctrlcount > 1 ? "s" : "", input);
  334.     X        (void) fclose (ioptr);
  335.     X        return (0);
  336.     X        }
  337.     X    else
  338.     X        {
  339.     X        fprintf (stderr, "shar: Can't open '%s'\n", input);
  340.     X        return (1);
  341.     X        }
  342.     X    }
  343.     X
  344.     X/*
  345.     X    Copyout copies its ioptr almost as fast as possible
  346.     X    except that it has to keep track of the last character
  347.     X    printed.  If the last character is not a newline, then
  348.     X    shar has to add one so that the end of file delimiter
  349.     X    is recognized by the shell.  This checking costs about
  350.     X    a 10% difference in user time.  Otherwise, it is about
  351.     X    as fast as cat.  It also might count control characters.
  352.     X*/
  353.     X#define    badctrl(c) (iscntrl (c) && !isspace (c))
  354.     Xcopyout (ioptr)
  355.     Xregister    FILE    *ioptr;
  356.     X    {
  357.     X    register    int     C;
  358.     X    register    int     L;
  359.     X    register    count;
  360.     X    count = Count;
  361.     X    while ((C = getc (ioptr)) != EOF)
  362.     X        {
  363.     X        if (count == true && badctrl (C)) Ctrlcount++;
  364.     X        L = putchar (C);
  365.     X        }
  366.     X    Lastchar = L;
  367.     X    }
  368.     X
  369.     Xoutline (s)
  370.     Xregister    char    *s;
  371.     X    {
  372.     X    if (*s)
  373.     X        {
  374.     X        while (*s)
  375.     X            {
  376.     X            if (Count == true && badctrl (*s)) Ctrlcount++;
  377.     X            putchar (*s++);
  378.     X            }
  379.     X        Lastchar = *(s-1);
  380.     X        }
  381.     X    }
  382.     X
  383.     X#define    FSIZE     statbuf.st_size
  384.     Xshar (file, type, pos)
  385.     Xchar    *file;     /* file or directory to be processed */
  386.     Xint     type;      /* either 'f' for file or 'd' for directory */
  387.     Xint     pos;       /* 0 going in to a file or dir, 1 going out */
  388.     X    {
  389.     X    struct    stat    statbuf;
  390.     X    char    *basefile = file;
  391.     X    if (!strcmp (file, ".")) return;
  392.     X    if (stat (file, &statbuf)) FSIZE = 0;
  393.     X    if (Basename == true)
  394.     X        {
  395.     X        while (*basefile) basefile++; /* go to end of name */
  396.     X        while (basefile > file && *(basefile-1) != '/') basefile--;
  397.     X        }
  398.     X    if (pos == 0) /* before the file starts */
  399.     X        {
  400.     X        if (type == 'd')
  401.     X            {
  402.     X            printf ("if %s ! -d '%s'\n", TEST, basefile);
  403.     X            printf ("then\n");
  404.     X            if (Verbose == true)
  405.     X                printf ("    %s: creating directory \"'%s'\"\n", ECHO, basefile);
  406.     X            printf ("    %s '%s'\n", MKDIR, basefile);
  407.     X            printf ("fi\n");
  408.     X            if (Verbose == true)
  409.     X                printf ("%s: entering directory \"'%s'\"\n", ECHO, basefile);
  410.     X            printf ("%s '%s'\n", CHDIR, basefile);
  411.     X            }
  412.     X        else /* type == 'f' */
  413.     X            {
  414.     X            if (Verbose == true)
  415.     X                printf ("%s: extracting \"'%s'\" '(%d character%s)'\n",
  416.     X                    ECHO, basefile, FSIZE, FSIZE > 1 ? "s" : "");
  417.     X            if (Silent == false) /* this solution by G|ran Uddeborg */
  418.     X                {
  419.     X                printf ("if %s -f '%s'\n", TEST, basefile);
  420.     X                puts ("then");
  421.     X                printf ("    %s: will not over-write existing file \"'%s'\"\n",
  422.     X                    ECHO, basefile);
  423.     X                puts ("else");
  424.     X                }
  425.     X            if (archive (file, basefile)) exit (-1);
  426.     X            }
  427.     X        }
  428.     X    else /* pos == 1, after the file is archived */
  429.     X        {
  430.     X        if (type == 'd')
  431.     X            {
  432.     X            if (Verbose == true)
  433.     X                printf ("%s: done with directory \"'%s'\"\n", ECHO, basefile);
  434.     X            printf ("%s ..\n", CHDIR);
  435.     X            }
  436.     X        else /* type == 'f' (plain file) */
  437.     X            {
  438.     X            if (Count == true)
  439.     X                {
  440.     X                printf ("if %s %d -ne \"`%s '%s'`\"\n",
  441.     X                    TEST, FSIZE, WC_C, basefile);
  442.     X                puts ("then");
  443.     X                printf ("    %s: error transmitting \"'%s'\" ", ECHO, basefile);
  444.     X                printf ("'(should have been %d character%s)'\n",
  445.     X                    FSIZE, FSIZE > 1 ? "s" : "");
  446.     X                puts ("fi");
  447.     X                }
  448.     X            if (access (file, 1) == 0) /* executable -> chmod +x */
  449.     X                printf ("%s '%s'\n", CHMOD, basefile);
  450.     X            if (Silent == false)
  451.     X                {
  452.     X                puts ("fi # end of overwriting check");
  453.     X                }
  454.     X            }
  455.     X        }
  456.     X    }
  457. SHAR_EOF
  458. if test 8881 -ne "`wc -c < 'shar.c'`"
  459. then
  460.     echo shar: error transmitting "'shar.c'" '(should have been 8881 characters)'
  461. fi
  462. fi # end of overwriting check
  463. echo shar: extracting "'traverse.3'" '(1169 characters)'
  464. if test -f 'traverse.3'
  465. then
  466.     echo shar: will not over-write existing file "'traverse.3'"
  467. else
  468. sed 's/^    X//' << \SHAR_EOF > 'traverse.3'
  469.     X.TH TRAVERSE 3WI "December 16, 1984"
  470.     X.SH NAME
  471.     Xtraverse \- recursively traverse a directory
  472.     X.SH SYNOPSIS
  473.     X.nf
  474.     Xtraverse (path, func)
  475.     Xchar    *path;
  476.     Xint     (*func) ();
  477.     X
  478.     Xfunc (path, filetype, position)
  479.     Xchar    *path;
  480.     X.fi
  481.     X.SH DESCRIPTION
  482.     Xtraverse
  483.     Xapplies its argument function func to its argument file pathname path.
  484.     XIf path is a directory,
  485.     Xthen traverse applies func to all its entries.
  486.     XThis traversal is in depth first order
  487.     Xso that files are processed in the order
  488.     Xthat they are stored in the directory.
  489.     X.PP
  490.     XThe argument func should take three parameters:
  491.     Xa file name,
  492.     Xa file type,
  493.     Xand a position.
  494.     XThe call looks like this for directories:
  495.     X.ce
  496.     X(*func) (path, 'd', position);
  497.     Xand like this for other files:
  498.     X.ce
  499.     X(*func) (path, 'f', position);
  500.     XThe position
  501.     Xis 0 when path is first encountered
  502.     Xand 1 when traverse is done.
  503.     XThis is used to allow processing before and after
  504.     Xa directory is processed.
  505.     X.SH EXAMPLE
  506.     X.nf
  507.     Xlist (name, type, pos)
  508.     Xchar    *name;
  509.     X    {
  510.     X    if (type == 'd')
  511.     X        printf ("%s %s\en", pos ? "Leaving" : "Entering", name);
  512.     X    else /* type == 'f' */
  513.     X        printf ("    %s\en", name);
  514.     X    }
  515.     X.fi
  516.     X.SH AUTHOR
  517.     XGary Perlman
  518.     X.SH BUGS
  519.     XThere are no diagnostics when directories cannot be searched.
  520. SHAR_EOF
  521. if test 1169 -ne "`wc -c < 'traverse.3'`"
  522. then
  523.     echo shar: error transmitting "'traverse.3'" '(should have been 1169 characters)'
  524. fi
  525. fi # end of overwriting check
  526. echo shar: extracting "'traverse.c'" '(1769 characters)'
  527. if test -f 'traverse.c'
  528. then
  529.     echo shar: will not over-write existing file "'traverse.c'"
  530. else
  531. sed 's/^    X//' << \SHAR_EOF > 'traverse.c'
  532.     X/*LINTLIBRARY*/
  533.     X#include <stdio.h>
  534.     X#include <sys/types.h>
  535.     X#include <sys/dir.h>
  536.     X
  537.     X#ifdef MAXNAMLEN
  538.     X
  539.     X#define    namedir(entry) (entry->d_name)
  540.     X#define    MAXNAME 256
  541.     X
  542.     X#else
  543.     X
  544.     X#define    DIR    FILE
  545.     X#define    MAXNAME (DIRSIZ+2)
  546.     X#define    opendir(path) fopen (path, "r")
  547.     X#define closedir(dirp) fclose (dirp)
  548.     Xstruct direct *
  549.     Xreaddir (dirp)
  550.     XDIR     *dirp;
  551.     X    {
  552.     X    static    struct    direct    entry;
  553.     X    if (dirp == NULL) return (NULL);
  554.     X    for (;;)
  555.     X        {
  556.     X        if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) return (NULL);
  557.     X        if (entry.d_ino) return (&entry);
  558.     X        }
  559.     X    }
  560.     Xchar    *strncpy ();
  561.     Xchar *
  562.     Xnamedir (entry)
  563.     Xstruct    direct    *entry;
  564.     X    {
  565.     X    static    char    name[MAXNAME];
  566.     X    return (strncpy (name, entry->d_name, DIRSIZ));
  567.     X    }
  568.     X
  569.     X#endif
  570.     X
  571.     X#include <sys/stat.h>
  572.     X#define    isdir(path) (stat(path, &buf) ? 0 : (buf.st_mode&S_IFMT)==S_IFDIR)
  573.     X
  574.     Xtraverse (path, func)
  575.     Xchar    *path;
  576.     Xint     (*func) ();
  577.     X    {
  578.     X    DIR     *dirp;
  579.     X    struct    direct    *entry;
  580.     X    struct    stat    buf;
  581.     X    int     filetype = isdir (path) ? 'd' : 'f';
  582.     X    (*func) (path, filetype, 0);
  583.     X    if (filetype == 'd')
  584.     X        {
  585.     X        if (chdir (path) == 0)
  586.     X            {
  587.     X            if (dirp = opendir ("."))
  588.     X                {
  589.     X                while (entry = readdir (dirp))
  590.     X                    {
  591.     X                    char    name[MAXNAME];
  592.     X                    (void) strcpy (name, namedir (entry));
  593.     X                    if (strcmp(name, ".") && strcmp(name, ".."))
  594.     X                        traverse (name, func);
  595.     X                    }
  596.     X                (void) closedir(dirp);
  597.     X                }
  598.     X            (void) chdir ("..");
  599.     X            }
  600.     X        }
  601.     X    (*func) (path, filetype, 1);
  602.     X    }
  603.     X
  604.     X#ifdef STANDALONE
  605.     X
  606.     Xstatic    Indent = 0;
  607.     Xtryverse (file, type, pos)
  608.     Xchar    *file;
  609.     X    {
  610.     X    int     in;
  611.     X    if (pos == 0)
  612.     X        {
  613.     X        for (in = 0; in < Indent; in++) putchar ('\t');
  614.     X        if (type == 'd')
  615.     X            {
  616.     X            printf ("%s/\n", file);
  617.     X            Indent++;
  618.     X            }
  619.     X        else puts (file);
  620.     X        }
  621.     X    else if (type == 'd') Indent--;
  622.     X    }
  623.     X
  624.     Xmain (argc, argv) char **argv;
  625.     X    {
  626.     X    int     tryverse ();
  627.     X    char    *root = argc > 1 ? argv[1] : ".";
  628.     X    traverse (root, tryverse);
  629.     X    }
  630.     X#endif
  631. SHAR_EOF
  632. if test 1769 -ne "`wc -c < 'traverse.c'`"
  633. then
  634.     echo shar: error transmitting "'traverse.c'" '(should have been 1769 characters)'
  635. fi
  636. fi # end of overwriting check
  637. echo shar: extracting "'getopt.3'" '(2755 characters)'
  638. if test -f 'getopt.3'
  639. then
  640.     echo shar: will not over-write existing file "'getopt.3'"
  641. else
  642. sed 's/^    X//' << \SHAR_EOF > 'getopt.3'
  643.     X.TH GETOPT 3 local
  644.     X.DA 25 March 1982
  645.     X.SH NAME
  646.     Xgetopt \- get option letter from argv
  647.     X.SH SYNOPSIS
  648.     X.ft B
  649.     Xint getopt(argc, argv, optstring)
  650.     X.br
  651.     Xint argc;
  652.     X.br
  653.     Xchar **argv;
  654.     X.br
  655.     Xchar *optstring;
  656.     X.sp
  657.     Xextern char *optarg;
  658.     X.br
  659.     Xextern int optind;
  660.     X.ft
  661.     X.SH DESCRIPTION
  662.     X.I Getopt
  663.     Xreturns the next option letter in
  664.     X.I argv
  665.     Xthat matches a letter in
  666.     X.IR optstring .
  667.     X.I Optstring
  668.     Xis a string of recognized option letters;
  669.     Xif a letter is followed by a colon, the option is expected to have
  670.     Xan argument that may or may not be separated from it by white space.
  671.     X.I Optarg
  672.     Xis set to point to the start of the option argument on return from
  673.     X.IR getopt .
  674.     X.PP
  675.     X.I Getopt
  676.     Xplaces in
  677.     X.I optind
  678.     Xthe
  679.     X.I argv
  680.     Xindex of the next argument to be processed.
  681.     XBecause
  682.     X.I optind
  683.     Xis external, it is normally initialized to zero automatically
  684.     Xbefore the first call to 
  685.     X.IR getopt .
  686.     X.PP
  687.     XWhen all options have been processed (i.e., up to the first
  688.     Xnon-option argument),
  689.     X.I getopt
  690.     Xreturns
  691.     X.BR EOF .
  692.     XThe special option
  693.     X.B \-\-
  694.     Xmay be used to delimit the end of the options;
  695.     X.B EOF
  696.     Xwill be returned, and
  697.     X.B \-\-
  698.     Xwill be skipped.
  699.     X.SH SEE ALSO
  700.     Xgetopt(1)
  701.     X.SH DIAGNOSTICS
  702.     X.I Getopt
  703.     Xprints an error message on
  704.     X.I stderr
  705.     Xand returns a question mark
  706.     X.RB ( ? )
  707.     Xwhen it encounters an option letter not included in
  708.     X.IR optstring .
  709.     X.SH EXAMPLE
  710.     XThe following code fragment shows how one might process the arguments
  711.     Xfor a command that can take the mutually exclusive options
  712.     X.B a
  713.     Xand
  714.     X.BR b ,
  715.     Xand the options
  716.     X.B f
  717.     Xand
  718.     X.BR o ,
  719.     Xboth of which require arguments:
  720.     X.PP
  721.     X.RS
  722.     X.nf
  723.     Xmain(argc, argv)
  724.     Xint argc;
  725.     Xchar **argv;
  726.     X{
  727.     X    int c;
  728.     X    extern int optind;
  729.     X    extern char *optarg;
  730.     X    \&.
  731.     X    \&.
  732.     X    \&.
  733.     X    while ((c = getopt(argc, argv, "abf:o:")) != EOF)
  734.     X        switch (c) {
  735.     X        case 'a':
  736.     X            if (bflg)
  737.     X                errflg++;
  738.     X            else
  739.     X                aflg++;
  740.     X            break;
  741.     X        case 'b':
  742.     X            if (aflg)
  743.     X                errflg++;
  744.     X            else
  745.     X                bproc();
  746.     X            break;
  747.     X        case 'f':
  748.     X            ifile = optarg;
  749.     X            break;
  750.     X        case 'o':
  751.     X            ofile = optarg;
  752.     X            break;
  753.     X        case '?':
  754.     X        default:
  755.     X            errflg++;
  756.     X            break;
  757.     X        }
  758.     X    if (errflg) {
  759.     X        fprintf(stderr, "Usage: ...");
  760.     X        exit(2);
  761.     X    }
  762.     X    for (; optind < argc; optind++) {
  763.     X        \&.
  764.     X        \&.
  765.     X        \&.
  766.     X    }
  767.     X    \&.
  768.     X    \&.
  769.     X    \&.
  770.     X}
  771.     X.RE
  772.     X.PP
  773.     XA template similar to this can be found in
  774.     X.IR /usr/pub/template.c .
  775.     X.SH HISTORY
  776.     XWritten by Henry Spencer, working from a Bell Labs manual page.
  777.     XBehavior believed identical to the Bell version.
  778.     X.SH BUGS
  779.     XIt is not obvious how
  780.     X`\-'
  781.     Xstanding alone should be treated;  this version treats it as
  782.     Xa non-option argument, which is not always right.
  783.     X.PP
  784.     XOption arguments are allowed to begin with `\-';
  785.     Xthis is reasonable but reduces the amount of error checking possible.
  786.     X.PP
  787.     X.I Getopt
  788.     Xis quite flexible but the obvious price must be paid:  there is much
  789.     Xit could do that it doesn't, like
  790.     Xchecking mutually exclusive options, checking type of
  791.     Xoption arguments, etc.
  792. SHAR_EOF
  793. if test 2755 -ne "`wc -c < 'getopt.3'`"
  794. then
  795.     echo shar: error transmitting "'getopt.3'" '(should have been 2755 characters)'
  796. fi
  797. fi # end of overwriting check
  798. echo shar: extracting "'getopt.c'" '(1437 characters)'
  799. if test -f 'getopt.c'
  800. then
  801.     echo shar: will not over-write existing file "'getopt.c'"
  802. else
  803. sed 's/^    X//' << \SHAR_EOF > 'getopt.c'
  804.     X/* got this off net.sources */
  805.     X#include <stdio.h>
  806.     X
  807.     X/*
  808.     X * get option letter from argument vector
  809.     X */
  810.     Xint    opterr = 1,        /* useless, never set or used */
  811.     X    optind = 1,        /* index into parent argv vector */
  812.     X    optopt;            /* character checked for validity */
  813.     Xchar    *optarg;        /* argument associated with option */
  814.     X
  815.     X#define BADCH    (int)'?'
  816.     X#define EMSG    ""
  817.     X#define tell(s)    fputs(*nargv,stderr);fputs(s,stderr); \
  818.     X        fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
  819.     X
  820.     Xgetopt(nargc,nargv,ostr)
  821.     Xint    nargc;
  822.     Xchar    **nargv,
  823.     X    *ostr;
  824.     X{
  825.     X    static char    *place = EMSG;    /* option letter processing */
  826.     X    register char    *oli;        /* option letter list index */
  827.     X    char    *index();
  828.     X
  829.     X    if(!*place) {            /* update scanning pointer */
  830.     X        if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
  831.     X        if (*place == '-') {    /* found "--" */
  832.     X            ++optind;
  833.     X            return(EOF);
  834.     X        }
  835.     X    }                /* option letter okay? */
  836.     X    if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
  837.     X        if(!*place) ++optind;
  838.     X        tell(": illegal option -- ");
  839.     X    }
  840.     X    if (*++oli != ':') {        /* don't need argument */
  841.     X        optarg = NULL;
  842.     X        if (!*place) ++optind;
  843.     X    }
  844.     X    else {                /* need an argument */
  845.     X        if (*place) optarg = place;    /* no white space */
  846.     X        else if (nargc <= ++optind) {    /* no arg */
  847.     X            place = EMSG;
  848.     X            tell(": option requires an argument -- ");
  849.     X        }
  850.     X         else optarg = nargv[optind];    /* white space */
  851.     X        place = EMSG;
  852.     X        ++optind;
  853.     X    }
  854.     X    return(optopt);            /* dump back option letter */
  855.     X}
  856. SHAR_EOF
  857. if test 1437 -ne "`wc -c < 'getopt.c'`"
  858. then
  859.     echo shar: error transmitting "'getopt.c'" '(should have been 1437 characters)'
  860. fi
  861. fi # end of overwriting check
  862. echo shar: extracting "'Makefile'" '(142 characters)'
  863. if test -f 'Makefile'
  864. then
  865.     echo shar: will not over-write existing file "'Makefile'"
  866. else
  867. sed 's/^    X//' << \SHAR_EOF > 'Makefile'
  868.     XCFLAGS=-O
  869.     Xshar: shar.o traverse.o getopt.o
  870.     X    cc $(CFLAGS) -o shar shar.o traverse.o getopt.o
  871.     Xtraverse:
  872.     X    cc -o traverse -DSTANDALONE traverse.c
  873. SHAR_EOF
  874. if test 142 -ne "`wc -c < 'Makefile'`"
  875. then
  876.     echo shar: error transmitting "'Makefile'" '(should have been 142 characters)'
  877. fi
  878. fi # end of overwriting check
  879. #    End of shell archive
  880. exit 0
  881.  
  882.